﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Asset.cs" company="Anton Frattaroli">
//   Copyright (c) Anton Frattaroli. All rights reserved.
// </copyright>
// <summary>
//   Defines the Asset class.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Lidocaine
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Globalization;
    using System.IO;
    
    /// <summary>
    /// Defines the Asset class.
    /// </summary>
    public class Asset
    {
        #region Fields
        /// <summary>
        /// The identity of the database table's row where this file object is saved.
        /// </summary>
        private int fileID;

        /// <summary>
        /// Stores the file's filesystem path.
        /// </summary>
        private string filepath;

        /// <summary>
        /// Stores the file's URL path.
        /// </summary>
        private string virtualpath;

        /// <summary>
        /// The date and time the file entry was created.
        /// </summary>
        private DateTime created;

        /// <summary>
        /// Stores the file's filetype's database identity.
        /// </summary>
        private int filetypeID;

        /// <summary>
        /// Stores the file's filetype.
        /// </summary>
        private FileType filetype;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the Asset class.
        /// </summary>
        public Asset()
        {
        }

        /// <summary>
        /// Initializes a new instance of the Asset class.
        /// </summary>
        /// <param name="fileId">The identity of the database table's row referencing this file.</param>
        public Asset(int fileId)
        {
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.GetFileByID", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@FileID", fileId);
                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        if (rdr.HasRows)
                        {
                            rdr.Read();
                            this.fileID = fileId;
                            this.filepath = rdr["FilePath"].ToString();
                            this.virtualpath = rdr["VirtualPath"].ToString();
                            this.created = Convert.ToDateTime(rdr["Uploaded"], CultureInfo.InvariantCulture);
                            this.filetypeID = Convert.ToInt32(rdr["FileTypeID"], CultureInfo.InvariantCulture);
                        }
                        else
                        {
                            throw new DataException("File does not exist.");
                        }
                    }
                }
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the file's database row identity.
        /// </summary>
        public int FileId
        {
            get
            {
                return this.fileID;
            }
        }

        /// <summary>
        /// Gets or sets the file's filesystem path.
        /// </summary>
        public string FilePath
        {
            get
            {
                return this.filepath;
            }

            set
            {
                this.filepath = value;
            }
        }

        /// <summary>
        /// Gets or sets the file's URL path.
        /// </summary>
        public string VirtualPath
        {
            get
            {
                return this.virtualpath;
            }

            set
            {
                this.virtualpath = value;
            }
        }

        /// <summary>
        /// Gets the file's date and time it was created.
        /// </summary>
        public DateTime Created
        {
            get
            {
                return this.created;
            }
        }

        /// <summary>
        /// Gets or sets the file's filetype.
        /// </summary>
        public FileType FileType
        {
            get
            {
                if (this.filetype == null && this.filetypeID != 0)
                {
                    this.filetype = new FileType(this.filetypeID);
                }

                return this.filetype;
            }

            set
            {
                this.filetype = value;
                this.filetypeID = value.FileTypeId;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Finds a list of files with a given file type.
        /// </summary>
        /// <param name="fileType">The filetype of the files to search for.</param>
        /// <returns>A read-only list of files.</returns>
        public static IList<Asset> GetFilesByFileType(FileType fileType)
        {
            List<Asset> h = new List<Asset>();
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.GetFilesByFileType", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@FileTypeID", fileType.FileTypeId);
                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        if (rdr.HasRows)
                        {
                            while (rdr.Read())
                            {
                                h.Add(new Asset(Convert.ToInt32(rdr["FileID"], CultureInfo.InvariantCulture)));
                            }
                        }
                    }
                }
            }

            return h.AsReadOnly();
        }
        
        /// <summary>
        /// Finds a file based on its virtual path, if it exists.
        /// </summary>
        /// <param name="virtualPath">The virtual path to search for.</param>
        /// <returns>If the file is found, an HFile is populated and returned. Returns null otherwise.</returns>
        public static Asset GetFileByVirtualPath(string virtualPath)
        {
            Asset h = null;
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.GetFileByVirtualPath", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@VirtualPath", virtualPath);
                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        if (rdr.HasRows)
                        {
                            rdr.Read();
                            h = new Asset();
                            h.fileID = Convert.ToInt32(rdr["FileID"], CultureInfo.InvariantCulture);
                            h.filepath = rdr["FilePath"].ToString();
                            h.virtualpath = virtualPath;
                            h.created = Convert.ToDateTime(rdr["Uploaded"], CultureInfo.InvariantCulture);
                            h.filetypeID = Convert.ToInt32(rdr["FileTypeID"], CultureInfo.InvariantCulture);
                        }
                    }
                }
            }

            return h;
        }
        
        /// <summary>
        /// Inserts the HFile object into the database.
        /// </summary>
        public void SaveAs()
        {
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.InsertFile", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@VirtualPath", this.virtualpath);
                    if (this.filetypeID == 0)
                    {
                        cmd.Parameters.AddWithValue("@FileTypeID", DBNull.Value);
                    }
                    else
                    {
                        cmd.Parameters.AddWithValue("@FileTypeID", this.filetypeID);
                    }

                    this.fileID = Convert.ToInt32(cmd.ExecuteScalar(), CultureInfo.InvariantCulture);
                }
            }
        }

        /// <summary>
        /// Updates the HFile's database fields.
        /// </summary>
        public void Save()
        {
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.UpdateFile", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@FileID", this.fileID);
                    cmd.Parameters.AddWithValue("@FilePath", this.filepath);
                    cmd.Parameters.AddWithValue("@VirtualPath", this.virtualpath);
                    if (this.filetypeID == 0)
                    {
                        cmd.Parameters.AddWithValue("@FileTypeID", DBNull.Value);
                    }
                    else
                    {
                        cmd.Parameters.AddWithValue("@FileTypeID", this.filetypeID);
                    }

                    cmd.ExecuteNonQuery();
                }
            }
        }

        /// <summary>
        /// Deletes the HFile's database entry.
        /// </summary>
        public virtual void Delete()
        {
            using (SqlConnection conn = new SqlConnection(Environmental.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("Lidocaine.DeleteFile", conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@FileID", this.fileID);
                    cmd.ExecuteNonQuery();
                }
            }
        }
        #endregion
    }
}
